/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * This example is a more complex and has signal-handler and options in
 * addition to demonstrating how to modify sizes of receiving messagequeues
 * and sending data.
 *
 */
#include <signal.h>

#include "gimi.h"

volatile bool active = true;
gimi::GIMI* gimipointer = NULL; // A global pointer to GIMI-object needed by
                                // signal-handler.

/**
 * Signal-handler method. When a signal arrives to program this method decides
 * what should be done. (pressing CTRL-C sends SIGINT to program)
 */
static void sig_handler(int signumber, siginfo_t *info, void *context)
{
  /* If interrupt signal received, stop loops */
  if (info->si_signo == SIGINT) {
    dPrint(1, "Got SIGINT. Stopping loops.");
    active = false;
    if (gimipointer != NULL)
      gimipointer->stop();
    else
      dPrint(1, "Could not find GIMI-object to stop. Receive/ping/serviceDiscovery"
          "-methods won't quit until timeout.");
  } else if (info->si_signo == SIGTERM) {
    dPrint(1, "Got SIGTERM. Stopping loops.");
    active = false;
    if (gimipointer != NULL)
      gimipointer->stop();
    else
      dPrint(1, "Could not find GIMI-object to stop. Receive/ping/serviceDiscovery"
          "-methods won't quit until timeout.");
  } else {
    dPrint(1, "Got signal %d", info->si_signo);
  }

  return;
}

void printUsage()
{
  printf("-r [interval] Sets program on receive mode, messages read with given interval in ms.\n");
  printf("-t [target]   Sends data to target when not in receive mode.\n");
  printf("[data]        Data that is sent to target.\n");
}

int main(int argc, char **argv) {
  std::string hubname = "asrobo.hut.fi";
  int hubport = 50002;
  std::string ownname = "gimitutorialmisc";
  std::string targetname = "gimitutorialreceiver";
  std::string data = "";
  int interval = -1;

  bool parameterParseLoop = true, receiveMode = false;
  int result, option_char;

  // Variables for signal handling
  struct sigaction siga;

  // Initialize dPrint.
  debugInit();
  debugSetGlobalDebugLvl(6);

  /*** Set options ***/
  while (parameterParseLoop) {
    option_char = getopt(argc, argv, "r:t:");
    switch (option_char) {
      case 'r':
        if (optarg != NULL)
          interval = atoi(optarg);
        receiveMode = true;
        ownname = "gimitutorialreceiver";
        break;
      case 't':
        if (optarg != NULL)
          targetname = optarg;
        dPrint(6, "Targetname set to: %s", targetname.c_str());
      case '?':
        printUsage();
        return 1;
        break;
      case -1:
        parameterParseLoop = false;
        break;
    }
  }
  if (optind < argc) { // Parse data 
    while (optind < argc) {
      data += argv[optind++];
      if (optind < argc) {
        data += " ";
      }
    }
  }

  if ((receiveMode && interval < 0) || (!receiveMode && data.empty())) {
    printUsage();
    return 1;
  }
  
  // Create the GIMI-object with shorter messagequeues
  dPrint(1, "Create object.");
  gimi::GIMI gi(10);

  // Get pointer to object for signal-handler.
  gimipointer = &gi;

  // Create message-object for receiving.
  gimi::GIMIMessage message;
  
  // Turn on signal-handling
  sigemptyset(&siga.sa_mask);
  siga.sa_flags = SA_SIGINFO;
  siga.sa_sigaction = sig_handler;
  // Set signals we can handle
  sigaction(SIGINT, &siga, NULL);
  sigaction(SIGTERM, &siga, NULL);
  
  // Connect to tcphub.
  if (!gi.connectToHub(hubname, hubport, ownname)) {
    dPrint(1, "Could not connect to tcpHub. Are connection parameters correct?");
    return -1;
  }

  dPrint(1, "Connected to hub. My id is %d.", gi.getOwnId());
  
  if (receiveMode) { // Receive only mode.
    // Set maximum size for messagequeue of type 8000:0 (major:minor) to 1,
    // so only the newest message is kept in the queue.
    if (gi.setQueueMaxSize(8000, 0, 1) != true) {
      dPrint(1, "Setting new maximum size for messagequeue 8000:0 failed.");
    }

    // Message listening-loop, timeout -1 waits until a message arrives to queue.
    while (active) {
      result = gi.receive(message, -1);
      if (result == GIMI_OK) {
        printf("Got message with majortype: %d minortype: %d msgid: %d "
            "from: 0x%08x with flags: %d arrived: %ld.06%ld s data: ",
            message.majorTypeId, message.minorTypeId, message.messageId,
            message.senderId, message.messageFlags, message.arrivalTime.seconds,
            message.arrivalTime.useconds);
        for(int n=0; n < message.datalength; ++n) {
          printf("%c", message.data[n]);
        }
        printf("\n");
      } else if (result == GIMI_INTERRUPT) {
        printf("Receive was interrupted.\n");
      } else {
        printf("Got error %d (%s) from receive, not OK.\n", result,
               gimi::getGimiErrorString(result).c_str());
      }
      if (interval > 0)
        ownSleep_ms(interval); // Adjustable interval so effects of
                               // short messagequeue length can be shown.
    }
    printf("Quitting.\n");
  } else { // Sending mode.
    int msgid = 0;

    // Find id of target.
    int clientid = gi.findClientId(targetname);

    if (clientid < 0) {
      printf("Error %d occurred finding clientid for %s\n", clientid,
             targetname.c_str());
    } else if (clientid == 0) {
      printf("Could not find clientid for %s.\n", targetname.c_str());
    } else {
      printf("Clientid of %s is %d.\n", targetname.c_str(), clientid);
    }
    
    // Send a ping to target.
    result = gi.ping(targetname, 500);

    if (result >= 0) { // Send data if ping succeeded.
      printf("Pinging %s success. Took %dms\n", targetname.c_str(), result);
      //NOTE Pinging before send is NOT necessary, it is done here only as an example.
      while (active) {
        if(gi.send(targetname, data.c_str(), data.length(), 8000, 0, msgid)
          != GIMI_OK) {
          printf("Sending failed.\n");
        } else {
          printf("Message %d sent.\n", msgid);
          ++msgid;
        }
        ownSleep_ms(50); // Send is done every 50ms.
      }
    } else {
      printf("Pinging %s failed with error %d, sending aborted.\n",
             targetname.c_str(), result);
    }
  }

  // Closes logfile in case if it was used. (dPrint)
  debugDeinit();
  
  return 0;
}
